"""
Cython集成模块

提供Cython优化比对逻辑的Python接口，与现有系统无缝集成
"""

import logging
import time
import numpy as np
from typing import List, Dict, Tuple, Optional, Any
import traceback

# 尝试导入Cython模块
try:
    from cython_frame_comparer import CythonFrameComparer, fast_find_differences, vectorized_frame_hash
    from cython_data_extractor import FastDataExtractor, batch_extract_vc_info, extract_comparison_data_fast
    CYTHON_AVAILABLE = True
    print("✓ Cython模块加载成功，将使用高性能比对")
except ImportError as e:
    CYTHON_AVAILABLE = False
    print(f"⚠ Cython模块不可用，将使用NumPy版本: {e}")
    # 提供备用实现
    class CythonFrameComparer:
        def __init__(self, max_diff_reports=100, use_parallel=True):
            self.max_diff_reports = max_diff_reports
            
        def compare_payloads_detailed(self, payload1, payload2, compare_range=None):
            return {"type": "fallback", "message": "Cython不可用"}
            
        def batch_compare_payloads(self, payloads1, payloads2, compare_range=None):
            return [False] * len(payloads1)
    
    class FastDataExtractor:
        @staticmethod
        def extract_virtual_channel_frame_count_fast(payload, frame_format):
            return 0
            
        @staticmethod
        def extract_virtual_channel_fast(payload, frame_format):
            return 0

class CythonCompareEngine:
    """Cython比对引擎
    
    提供高性能的帧比对功能，与现有接口兼容
    """
    
    def __init__(self, max_diff_reports: int = 100, use_parallel: bool = True):
        """初始化Cython比对引擎
        
        Args:
            max_diff_reports: 最大差异报告数量
            use_parallel: 是否使用并行处理
        """
        self.logger = logging.getLogger('cython_comparer')
        self.max_diff_reports = max_diff_reports
        self.use_parallel = use_parallel
        self.cython_available = CYTHON_AVAILABLE
        
        if CYTHON_AVAILABLE:
            self.comparer = CythonFrameComparer(max_diff_reports, use_parallel)
            self.logger.info("Cython比对引擎初始化成功")
        else:
            self.comparer = None
            self.logger.warning("Cython不可用，比对性能将受到影响")
    
    def is_available(self) -> bool:
        """检查Cython是否可用"""
        return self.cython_available
    
    def get_performance_info(self) -> Dict[str, Any]:
        """获取性能信息"""
        return {
            'cython_available': self.cython_available,
            'parallel_support': self.use_parallel,
            'max_diff_reports': self.max_diff_reports,
            'expected_speedup': '5-15x' if self.cython_available else '1x'
        }
    
    def extract_virtual_channel_info_fast(self, frames: List[Dict], frame_format: str) -> Tuple[List[int], List[int]]:
        """快速提取虚拟信道信息
        
        Args:
            frames: 帧列表
            frame_format: 帧格式
            
        Returns:
            tuple: (虚拟信道列表, 帧计数列表)
        """
        try:
            if self.cython_available and len(frames) > 100:
                # 大量数据使用Cython批量处理
                return batch_extract_vc_info(frames, frame_format)
            else:
                # 小量数据或Cython不可用时使用原有逻辑
                return self._extract_vc_info_fallback(frames, frame_format)
        except Exception as e:
            self.logger.error(f"虚拟信道信息提取失败: {e}")
            return self._extract_vc_info_fallback(frames, frame_format)
    
    def _extract_vc_info_fallback(self, frames: List[Dict], frame_format: str) -> Tuple[List[int], List[int]]:
        """备用的虚拟信道信息提取"""
        vc_ids = []
        frame_counts = []
        
        for frame in frames:
            # 使用现有的提取逻辑
            from frame_processor import FrameProcessor
            vc_id = int(frame.get('virtual_channel', 0))
            frame_count = FrameProcessor.extract_virtual_channel_frame_count(frame)
            
            vc_ids.append(vc_id)
            frame_counts.append(frame_count)
        
        return vc_ids, frame_counts
    
    def compare_frames_detailed(self, frame1: Dict, frame2: Dict, 
                              compare_range: Optional[Tuple[int, int]] = None) -> Dict:
        """详细比对两个帧
        
        Args:
            frame1: 基准帧
            frame2: 目标帧
            compare_range: 比对范围
            
        Returns:
            dict: 比对结果
        """
        try:
            if not self.cython_available:
                return self._compare_frames_fallback(frame1, frame2, compare_range)
            
            # 准备payload数据
            payload1 = self._prepare_payload(frame1['payload'])
            payload2 = self._prepare_payload(frame2['payload'])
            
            # 使用Cython比对
            start_time = time.time()
            result = self.comparer.compare_payloads_detailed(payload1, payload2, compare_range)
            elapsed = time.time() - start_time
            
            # 添加性能信息
            result['performance'] = {
                'method': 'cython',
                'elapsed_time': elapsed,
                'speedup_estimated': '5-15x'
            }
            
            return result
            
        except Exception as e:
            self.logger.error(f"Cython比对失败，回退到备用方法: {e}")
            return self._compare_frames_fallback(frame1, frame2, compare_range)
    
    def _prepare_payload(self, payload) -> np.ndarray:
        """准备payload数据为NumPy数组"""
        if isinstance(payload, bytes):
            return np.frombuffer(payload, dtype=np.uint8)
        elif isinstance(payload, (list, tuple)):
            return np.array(payload, dtype=np.uint8)
        elif isinstance(payload, np.ndarray):
            return payload.astype(np.uint8)
        else:
            raise ValueError(f"不支持的payload类型: {type(payload)}")
    
    def _compare_frames_fallback(self, frame1: Dict, frame2: Dict, 
                               compare_range: Optional[Tuple[int, int]] = None) -> Dict:
        """备用的帧比对方法（使用NumPy）"""
        try:
            payload1 = self._prepare_payload(frame1['payload'])
            payload2 = self._prepare_payload(frame2['payload'])
            
            # 应用比对范围
            if compare_range:
                start, end = compare_range
                payload1 = payload1[start:end+1]
                payload2 = payload2[start:end+1]
            
            # 长度检查
            if len(payload1) != len(payload2):
                return {
                    'type': 'length_mismatch',
                    'length1': len(payload1),
                    'length2': len(payload2),
                    'performance': {'method': 'numpy_fallback'}
                }
            
            # NumPy比对
            if np.array_equal(payload1, payload2):
                return {
                    'type': 'matching',
                    'performance': {'method': 'numpy_fallback'}
                }
            
            # 查找差异
            diff_indices = np.where(payload1 != payload2)[0]
            differences = []
            
            for i, idx in enumerate(diff_indices[:self.max_diff_reports]):
                actual_pos = int(idx)
                if compare_range:
                    actual_pos += compare_range[0]
                
                differences.append({
                    'byte_position': actual_pos,
                    'value1': int(payload1[idx]),
                    'value2': int(payload2[idx]),
                    'diff_bits': bin(int(payload1[idx]) ^ int(payload2[idx]))[2:].zfill(8)
                })
            
            result = {
                'type': 'content_mismatch',
                'total_differences': len(diff_indices),
                'reported_differences': len(differences),
                'differences': differences,
                'performance': {'method': 'numpy_fallback'}
            }
            
            if len(diff_indices) > self.max_diff_reports:
                result['truncated'] = True
                result['max_reports'] = self.max_diff_reports
            
            return result
            
        except Exception as e:
            return {
                'type': 'error',
                'message': str(e),
                'performance': {'method': 'numpy_fallback'}
            }
    
    def batch_compare_payloads(self, payloads1: List, payloads2: List, 
                             compare_range: Optional[Tuple[int, int]] = None) -> List[bool]:
        """批量比对payload数据
        
        Args:
            payloads1: 第一组payload列表
            payloads2: 第二组payload列表
            compare_range: 比对范围
            
        Returns:
            list: 比对结果列表（True表示匹配）
        """
        try:
            if self.cython_available and len(payloads1) > 50:
                # 大批量数据使用Cython
                start_time = time.time()
                results = self.comparer.batch_compare_payloads(payloads1, payloads2, compare_range)
                elapsed = time.time() - start_time
                self.logger.debug(f"Cython批量比对完成: {len(payloads1)}个payload, 耗时{elapsed:.3f}秒")
                return results
            else:
                # 小批量数据或Cython不可用时使用NumPy
                return self._batch_compare_fallback(payloads1, payloads2, compare_range)
                
        except Exception as e:
            self.logger.error(f"Cython批量比对失败，回退到NumPy: {e}")
            return self._batch_compare_fallback(payloads1, payloads2, compare_range)
    
    def _batch_compare_fallback(self, payloads1: List, payloads2: List, 
                              compare_range: Optional[Tuple[int, int]] = None) -> List[bool]:
        """备用的批量比对方法"""
        results = []
        
        for p1, p2 in zip(payloads1, payloads2):
            try:
                arr1 = self._prepare_payload(p1)
                arr2 = self._prepare_payload(p2)
                
                if compare_range:
                    start, end = compare_range
                    arr1 = arr1[start:end+1]
                    arr2 = arr2[start:end+1]
                
                is_equal = np.array_equal(arr1, arr2)
                results.append(is_equal)
                
            except Exception as e:
                self.logger.error(f"批量比对单项失败: {e}")
                results.append(False)
        
        return results
    
    def extract_comparison_data(self, frame: Dict, compare_range: Optional[Tuple[int, int]] = None, 
                              frame_format: str = '1092') -> np.ndarray:
        """提取用于比对的数据
        
        Args:
            frame: 帧数据
            compare_range: 比对范围
            frame_format: 帧格式
            
        Returns:
            numpy.ndarray: 提取的数据
        """
        try:
            payload = self._prepare_payload(frame['payload'])
            
            if self.cython_available:
                return extract_comparison_data_fast(payload, compare_range, frame_format)
            else:
                # 备用实现
                max_len = len(payload)
                if frame_format == '1092':
                    max_len = min(max_len, 1024)
                elif frame_format == '896':
                    max_len = min(max_len, 896)
                
                if compare_range:
                    start, end = compare_range
                    start = max(0, start)
                    end = min(end, max_len - 1)
                    return payload[start:end+1]
                else:
                    return payload[:max_len]
                    
        except Exception as e:
            self.logger.error(f"数据提取失败: {e}")
            return np.array([], dtype=np.uint8)


# 全局Cython引擎实例
_cython_engine = None

def get_cython_engine(max_diff_reports: int = 100, use_parallel: bool = True) -> CythonCompareEngine:
    """获取全局Cython比对引擎实例
    
    Args:
        max_diff_reports: 最大差异报告数量
        use_parallel: 是否使用并行处理
        
    Returns:
        CythonCompareEngine: Cython比对引擎
    """
    global _cython_engine
    
    if _cython_engine is None:
        _cython_engine = CythonCompareEngine(max_diff_reports, use_parallel)
    
    return _cython_engine

def check_cython_performance(test_size: int = 1000) -> Dict[str, Any]:
    """检查Cython性能
    
    Args:
        test_size: 测试数据大小
        
    Returns:
        dict: 性能测试结果
    """
    engine = get_cython_engine()
    
    # 生成测试数据
    test_data1 = np.random.randint(0, 256, test_size, dtype=np.uint8)
    test_data2 = test_data1.copy()
    test_data2[test_size//2:test_size//2+10] = 255  # 添加一些差异
    
    results = {
        'cython_available': engine.is_available(),
        'test_size': test_size,
        'performance': {}
    }
    
    if engine.is_available():
        try:
            # Cython性能测试
            start_time = time.time()
            cython_result = fast_find_differences(test_data1, test_data2, 100)
            cython_time = time.time() - start_time
            
            results['performance']['cython'] = {
                'time': cython_time,
                'differences_found': cython_result[0] if isinstance(cython_result, tuple) else 0
            }
        except Exception as e:
            results['performance']['cython'] = {'error': str(e)}
    
    # NumPy性能测试（作为对比）
    try:
        start_time = time.time()
        diff_indices = np.where(test_data1 != test_data2)[0]
        numpy_time = time.time() - start_time
        
        results['performance']['numpy'] = {
            'time': numpy_time,
            'differences_found': len(diff_indices)
        }
        
        # 计算加速比
        if engine.is_available() and 'cython' in results['performance']:
            cython_time = results['performance']['cython'].get('time', 0)
            if cython_time > 0:
                speedup = numpy_time / cython_time
                results['speedup'] = f"{speedup:.1f}x"
            
    except Exception as e:
        results['performance']['numpy'] = {'error': str(e)}
    
    return results

if __name__ == "__main__":
    # 性能测试
    print("=== Cython性能测试 ===")
    
    # 检查可用性
    engine = get_cython_engine()
    print(f"Cython可用性: {engine.is_available()}")
    print(f"性能信息: {engine.get_performance_info()}")
    
    # 性能基准测试
    print("\n=== 性能基准测试 ===")
    for test_size in [1000, 10000, 100000]:
        print(f"\n测试数据大小: {test_size}")
        perf_result = check_cython_performance(test_size)
        
        if 'speedup' in perf_result:
            print(f"性能提升: {perf_result['speedup']}")
        
        if 'cython' in perf_result['performance']:
            cython_perf = perf_result['performance']['cython']
            print(f"Cython时间: {cython_perf.get('time', 'N/A'):.6f}秒")
        
        if 'numpy' in perf_result['performance']:
            numpy_perf = perf_result['performance']['numpy']
            print(f"NumPy时间: {numpy_perf.get('time', 'N/A'):.6f}秒") 